{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Python version: 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import os, time, sys\n",
    "import importlib as imp\n",
    "import matplotlib.pyplot as plt\n",
    "from tqdm import trange\n",
    "from time import sleep\n",
    "print(\"Python version: \" + sys.version)\n",
    "lumapi = imp.machinery.SourceFileLoader(\"lumepi\",\"D:\\\\Program Files\\\\Lumerical\\\\v202\\\\api\\\\python\\\\lumapi.py\").load_module()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "size = 5               # size of the network\n",
    "num_layer = 5          # number of the layers\n",
    "\n",
    "x_span = 400e-6        # pixel size: 400 um (400e-6*200 = 0.08)\n",
    "y_span = 400e-6\n",
    "z = 3e-2               # distance of propagation(the distance bewteen two layers)\n",
    "dist = 1e-2            # the distance bewteen the last layer and the detector plane\n",
    "\n",
    "height_map = np.load('./height_map.npy')         # load height_map\n",
    "filter_height_map = np.load('./filter_height_map.npy')\n",
    "\n",
    "hide = True                                     # hide the GUI will dramatically cut down the construction time\n",
    "\n",
    "material = \"<Object defined dielectric>\"        # VeroBlackPlus RGD875, refractive index: 1.7227\n",
    "refractive_index = 1.7227"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# construction progress bar\n",
    "def construction_progress_bar(iteration, total, prefix='', suffix= '', decimals = 2, fill='>'):\n",
    "    # percent format\n",
    "    length = 50\n",
    "    percent = ('{0:.' + str(decimals) + 'f}').format(100 * (iteration/float(total)))\n",
    "    filledlength = int(length * iteration // total)\n",
    "    bar = fill*filledlength + '-'*(length- filledlength)\n",
    "    print(f'\\r{prefix}|{bar}|{percent}% {suffix}',end = '\\r')\n",
    "    if iteration == total:\n",
    "        print()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Estimated construction time: 0.0011111111111111111 hours\n",
      "Progress|>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>|100.00% Complete\n"
     ]
    }
   ],
   "source": [
    "estimated_construction_time = 0.032*(num_layer+1)*size*size/3600\n",
    "print(\"Estimated construction time: \" + str(estimated_construction_time)+ \" hours\")\n",
    "\n",
    "fdtd = lumapi.FDTD(hide = hide)   # hide the GUI of the software\n",
    "\n",
    "# add a filter behind the source\n",
    "counter = 0                                                 # counter: count the number of constructed rects\n",
    "fdtd.addstructuregroup()\n",
    "fdtd.set(\"name\",\"filter\")\n",
    "fdtd.groupscope(\"filter\")\n",
    "for j in range(0,size):                                     # i:x-axis, j: y-axis\n",
    "        for i in range(0,size):\n",
    "            fdtd.addrect()                                  # create and select the rect\n",
    "            fdtd.set(\"name\",\"filter\"+str(i)+\"_\"+str(j))       # set the name of the little rect\n",
    "            fdtd.set(\"x\",x_span/2 + i*x_span)               # set the x center position of the rect\n",
    "            fdtd.set(\"x span\",x_span)\n",
    "            fdtd.set(\"y\",-y_span/2 - j*y_span)              # set the y center position of the rect\n",
    "            fdtd.set(\"y span\",y_span)  \n",
    "            fdtd.set(\"z min\",-1*z)              # set the z center position of the rect\n",
    "            fdtd.set(\"z max\",-1*z + filter_height_map[j][i])\n",
    "            fdtd.set(\"material\",material)\n",
    "            fdtd.set(\"index\",refractive_index)\n",
    "            counter+=1\n",
    "            construction_progress_bar(iteration=counter , total=(num_layer+1)*size*size,prefix = 'Progress', suffix='Complete')\n",
    "fdtd.groupscope(\"::model\")\n",
    "\n",
    "\n",
    "def override_layer_mesh(layer_name,num_layer,layer_z_position):\n",
    "    fdtd.groupscope(\"::model\")\n",
    "    fdtd.addmesh()\n",
    "    fdtd.set(\"name\",layer_name + \"mesh\")\n",
    "    # set dimension\n",
    "    fdtd.set(\"x\",size*x_span/2)\n",
    "    fdtd.set('x span',size*x_span)      \n",
    "    fdtd.set(\"y\",-1*size*y_span/2)    \n",
    "    fdtd.set(\"y span\",size*x_span)\n",
    "    fdtd.set(\"z max\",layer_z_position)\n",
    "    fdtd.set(\"z min\",layer_z_position - np.max(height_map[num_layer]))          # 这个值是height_map里面最厚的那个值                            \n",
    "    # enable in X,Y,Z direction\n",
    "    # 1:enable, 0:disable\n",
    "    fdtd.set(\"override x mesh\",1)\n",
    "    fdtd.set(\"override y mesh\",1)\n",
    "    fdtd.set(\"override z mesh\",1)\n",
    "    # restrict mesh by defining maximum step size\n",
    "    fdtd.set(\"set maximum mesh step\",1)\n",
    "    fdtd.set(\"dx\",100e-6)\n",
    "    fdtd.set(\"dy\",100e-6)\n",
    "    fdtd.set(\"dz\",100e-6)\n",
    "    return None\n",
    "\n",
    "# add diffraction layers\n",
    "for l in range(0,num_layer):                                # l is the layer number\n",
    "    fdtd.addstructuregroup()\n",
    "    groupname = \"diffraction_layer_\"+ str(l)                # one group represents one layer\n",
    "    fdtd.set(\"name\",groupname)\n",
    "    \n",
    "    fdtd.groupscope(groupname)\n",
    "    layer_z_position = 0 + l*z\n",
    "    for j in range(0,size):                                 # i:x-axis, j: y-axis\n",
    "        for i in range(0,size):\n",
    "            fdtd.addrect()                                  # create and select the rect\n",
    "            fdtd.set(\"name\",\"rect\"+str(i)+\"_\"+str(j))       # set the name of the little rect\n",
    "            fdtd.set(\"x\",x_span/2 + i*x_span)               # set the x center position of the rect\n",
    "            fdtd.set(\"x span\",x_span)\n",
    "            fdtd.set(\"y\",-y_span/2 - j*y_span)              # set the y center position of the rect\n",
    "            fdtd.set(\"y span\",y_span)  \n",
    "            fdtd.set(\"z max\",0 + layer_z_position)              # set the z center position of the rect\n",
    "            fdtd.set(\"z min\",0 + layer_z_position - height_map[l][j][i])\n",
    "            fdtd.set(\"material\",material)\n",
    "            fdtd.set(\"index\",refractive_index)\n",
    "            counter+=1\n",
    "            # fdtd.addtogroup(groupname)\n",
    "            # display the progress of layer construction\n",
    "            construction_progress_bar(iteration=counter , total=(num_layer+1)*size*size,prefix = 'Progress', suffix='Complete')\n",
    "            \n",
    "    fdtd.groupscope(\"::model\")    # after create one layer, change the group scope back to the model\n",
    "    override_layer_mesh(layer_name = groupname,num_layer = l ,layer_z_position = layer_z_position)\n",
    "\n",
    "# add a plane wave source\n",
    "fdtd.addplane()\n",
    "fdtd.set(\"injection axis\",\"z\")\n",
    "fdtd.set(\"direction\",\"forward\") # propagate in the positive z direction\n",
    "fdtd.set(\"x\",size*x_span/2)\n",
    "fdtd.set(\"x span\",size*x_span)\n",
    "fdtd.set(\"y\",-1*size*y_span/2)\n",
    "fdtd.set(\"y span\",size*x_span)\n",
    "fdtd.set(\"z\",-1*z)\n",
    "fdtd.set(\"wavelength start\",750e-6)\n",
    "fdtd.set(\"wavelength stop\",750e-6)\n",
    "    \n",
    "\n",
    "# add monitor, the detector plane\n",
    "fdtd.addpower()\n",
    "fdtd.set('name','detector_plane_monitor')\n",
    "fdtd.set(\"x\",size*x_span/2)\n",
    "fdtd.set('x span',size*x_span)      \n",
    "fdtd.set(\"y\",-1*size*y_span/2)    \n",
    "fdtd.set(\"y span\",size*x_span)\n",
    "fdtd.set(\"z\",(num_layer-1)*z + dist)\n",
    "\n",
    "\n",
    "# add monitor, cross-sectional monitor\n",
    "fdtd.addprofile()                          # Frequency-domain field profile monitor\n",
    "fdtd.set('name','cross_sectional_monitor')\n",
    "fdtd.set(\"monitor type\",\"2D Y-normal\")     # x-z plane monitor\n",
    "fdtd.set(\"x\",size*x_span/2)\n",
    "fdtd.set('x span',size*x_span) \n",
    "fdtd.set(\"y\",-1*size*y_span/2)    \n",
    "fdtd.set(\"z min\",0-np.max(height_map[0]))\n",
    "fdtd.set(\"z max\",(num_layer-1)*z + dist)\n",
    "\n",
    "# add a simulation region\n",
    "fdtd.groupscope(\"::model\")\n",
    "fdtd.addfdtd()               \n",
    "fdtd.set('dimension',2)                 # 1 = 2D, 2 = 3D, set a 3D simulation region\n",
    "fdtd.set(\"x\",size*x_span/2)\n",
    "fdtd.set('x span',size*x_span)          # set the x span of the simulation region\n",
    "fdtd.set(\"y\",-1*size*y_span/2)          # we are using the negative part of the y-axis\n",
    "fdtd.set(\"y span\",size*x_span)\n",
    "fdtd.set(\"z max\",(num_layer-1)*z + dist)\n",
    "fdtd.set(\"z min\",-1*z)\n",
    "\n",
    "fdtd.save(\"D2NN_Simulation.fsp\")\n",
    "\n",
    "# run simulation\n",
    "# fdtd.run()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# get result and plot\n",
    "T = fdtd.getresult('monitor','time signal')\n",
    "S = fdtd.getresult('monitor','spectrum')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "fdtd.visualize(T) # 在软件里可视化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "# print(type(S))\n",
    "# print(S)\n",
    "# plt.plot(S['lambda'])\n",
    "# T['time']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
